#ifndef ABB_H
#define ABB_H

#include <stdbool.h>
#include <stddef.h>

/* ******************************************************************
 *                DEFINICION DE LOS TIPOS DE DATOS
 * *****************************************************************/

typedef struct abb abb_t;

typedef int (*abb_comparar_clave_t) (const char *, const char *);

typedef void (*abb_destruir_dato_t) (void *);

typedef struct abb_iter abb_iter_t;

/* ******************************************************************
 *                      PRIMITIVAS DEL ABB
 * *****************************************************************/

// Crea un abb.
// Pre: destruir_dato es una función capaz de destruir los
// datos del abb, o NULL en caso de que no se la utilice.
// cmp es una funcion que permite comparar las claves que se ingresaran.
// Post: devuelve NULL si no se pudo crear el abb, en caso
// contrario devuelve un nuevo abb vacío.
abb_t* abb_crear(abb_comparar_clave_t cmp, abb_destruir_dato_t destruir_dato);

// Agrega un nuevo par clave-dato al arbol. Devuelve falso en caso de error, en
// caso contrario devuelve true.
// Pre: el arbol, la clave y el dato fueron creados.
// Post: se agregó un nuevo par clave-dato al arbol.
bool abb_guardar(abb_t *arbol, const char *clave, void *dato);


// Borra la clave, pasada por parametro, del ABB.
// Pre: el ABB fue creado.
// Post: devuelve el dato asociado a la clave, se borra la clave del ABB
// que contiene un elemento menos. Si la clave no existe devuelve NULL.
void *abb_borrar(abb_t *arbol, const char *clave);

// Devuelve el dato asociado a la clave, en caso que la clave no pertenezca devuelve NULL.
// Pre: el ABB y la clave fueron creadas.
void *abb_obtener(const abb_t *arbol, const char *clave);

// Devuelve true si la clave pertenece al ABB, en caso que la clave no pertenezca devuelve NULL.
// Pre: el ABB y la clave fueron creadas.
bool abb_pertenece(const abb_t *arbol, const char *clave);

// Informa la cantidad de elementos en el abb.
// Pre: el arbol fue creado.
size_t abb_cantidad(abb_t *arbol);

// Destruye el arbol.
// Pre: el arbol fue creado.
// Post: se eliminaron todos los elementos del arbol. No devuelve nada.
void abb_destruir(abb_t *arbol);

/* ******************************************************************
 *                    PRIMITIVAS DE ITERACION
 * *****************************************************************/

// Crea un iterador.
// Pre: el ABB fue creado.
// Post: devuelve NULL si no se pudo crear el iterador, en caso contrario devuelve
// un iterador apuntando al primer elemento del ABB, o NULL si esta vacia.
abb_iter_t *abb_iter_in_crear(const abb_t *arbol);

// Avanza en el arbol al siguiente elemento respecto del actual.
// Pre: el iterador del arbol fue creado.
// Pos: devuelve true si pudo avanzar al siguiente elemento, en caso
// de no haber avanzado devuelve false.
bool abb_iter_in_avanzar(abb_iter_t *iter);

// Pre: el iterador de ABB fue creado.
// Post: devuelve la clave del elemento al que apunta el iterador, si el
// ABB esta vacio o el iterador apunta al final del ABB devuelve NULL.
const char *abb_iter_in_ver_actual(const abb_iter_t *iter);

// Informa si el iterador se encuentra al final del ABB.
// Pre: el iterador fue creado.
// Post: devuelve true si el iterador apunta al ultimo elemento, en
// caso contrario devuelve false.
bool abb_iter_in_al_final(const abb_iter_t *iter);

// Destruye el iterador.
// Pre: el iterador fue creado.
// Post: se eliminaron todos los elementos del iterador. No se devuelve nada.
void abb_iter_in_destruir(abb_iter_t* iter);

// Aplica la funcion visitar a los elementos del arbol.
// Pre: el arbol y la funcion visitar fueron creadas.
// Post: se aplico la funcion visitar a cada elemento del arbol hasta que se llego
// al final del mismo o cuando la funcion visitar devuelvio false. No se devuelve nada.
void abb_in_order(abb_t *arbol, bool visitar(const char *, void *, void *), void *extra);

#endif // ABB_H
